using System;
using System.IO;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using RTMP.SimpleClient.Exceptions;

namespace RTMP.SimpleClient.Helpers
{
    /// <summary>
    /// RTMP 握手助手类
    /// </summary>
    public static class RTMPHandshakeHelper
    {
        /// <summary>
        /// 执行 RTMP 握手过程
        /// </summary>
        /// <param name="networkStream">网络流</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>握手任务</returns>
        public static async Task PerformHandshakeAsync(NetworkStream networkStream, CancellationToken cancellationToken = default)
        {
            if (networkStream == null)
            {
                throw new ArgumentNullException(nameof(networkStream));
            }

            byte[] buffer = new byte[1536];
            byte[] randomData = new byte[1528];
            new Random().NextBytes(randomData);

            Span<byte> span = buffer.AsSpan();
            int clientTimeStamp = Environment.TickCount & 0x7FFFFFFF;

            // C0: 版本号
            span[0] = 0x03;
            await networkStream.WriteAsync(buffer, 0, 1, cancellationToken);

            span = buffer.AsSpan();
            // C1: 4字节时间戳 + 4字节0 + 1528字节随机数据
            clientTimeStamp.GetBigEndianSpan(span[..4]); //当前时间戳
            span.Slice(4, 4).Clear(); // 4字节0
            randomData.CopyTo(span.Slice(8, 1528)); // 随机数据
            await networkStream.WriteAsync(buffer, 0, buffer.Length, cancellationToken);

            // 读取 S0 并验证版本
            await networkStream.ReadExactlyAsync(buffer, 0, 1, cancellationToken);
            if (!ValidateServerVersion(buffer[0]))
            {
                throw new RTMPHandshakeException($"RTMP handshake failed: Invalid server version {buffer[0]:X2}, expected 0x03");
            }

            // 读取 S1
            await networkStream.ReadExactlyAsync(buffer, 0, buffer.Length, cancellationToken);
            span = buffer.AsSpan();
            int serverTimeStamp = span[4..8].BigEndianToInt32();
            Span<byte> serverRandomData = span[8..];
            Span<byte> clientRandomData = randomData.AsSpan();

            if (!serverRandomData.SequenceEqual(clientRandomData))
            {
                throw new RTMPHandshakeException("RTMP handshake failed: Invalid S1 packet structure");
            }

            // C2: 回显 S1
            serverTimeStamp.GetBigEndianSpan(span[..4]); // 服务器时间戳
            clientTimeStamp.GetBigEndianSpan(span[4..8]); // 客户端时间戳
            serverRandomData.CopyTo(span.Slice(8, 1528)); // 回显服务器随机数据
            await networkStream.WriteAsync(buffer, 0, buffer.Length, cancellationToken);

            // 读取 S2 并验证
            await networkStream.ReadExactlyAsync(buffer, 0, buffer.Length, cancellationToken);
            span = buffer.AsSpan();
            Span<byte> S2RandomData = span[8..];
            if (!S2RandomData.SequenceEqual(randomData.AsSpan()))
            {
                throw new RTMPHandshakeException("RTMP handshake failed: Invalid S2 packet structure");
            }
        }

        /// <summary>
        /// 验证服务器版本
        /// </summary>
        /// <param name="version">版本字节</param>
        /// <returns>是否为有效的RTMP版本</returns>
        public static bool ValidateServerVersion(byte version)
        {
            // RTMP协议版本必须是0x03
            return version == 0x03;
        }

        /// <summary>
        /// 验证握手数据包结构
        /// </summary>
        /// <param name="data">数据包</param>
        /// <param name="packetName">数据包名称（用于错误信息）</param>
        /// <returns>数据包结构是否有效</returns>
        public static bool ValidateHandshakePacket(byte[] data, string packetName)
        {
            if (data == null)
            {
                return false;
            }

            // RTMP握手数据包应该是1536字节随机数据 + 4字节时间戳 = 1540字节
            const int expectedLength = 1536 + 4;
            if (data.Length != expectedLength)
            {
                return false;
            }

            // 验证时间戳部分（前4字节）不为全零
            uint timestamp = BitConverter.ToUInt32(data, 0);
            if (timestamp == 0)
            {
                // 时间戳为0是允许的，但我们记录警告
                Console.WriteLine($"Warning: {packetName} timestamp is zero");
            }

            return true;
        }

        /// <summary>
        /// 验证回显数据
        /// </summary>
        /// <param name="echoData">回显数据</param>
        /// <param name="originalData">原始数据</param>
        /// <returns>回显数据是否正确</returns>
        public static bool ValidateEchoData(byte[] echoData, byte[] originalData)
        {
            if (echoData == null || originalData == null)
            {
                return false;
            }

            if (echoData.Length != originalData.Length)
            {
                return false;
            }

            // 比较前1528字节的随机数据（排除时间戳部分）
            const int randomDataLength = 1528;
            for (int i = 0; i < randomDataLength; i++)
            {
                if (echoData[i] != originalData[i])
                {
                    return false;
                }
            }

            // 时间戳部分应该被服务器更新，不需要完全匹配
            // 但我们可以验证它是一个合理的时间戳
            uint echoTimestamp = BitConverter.ToUInt32(echoData, 0);
            uint originalTimestamp = BitConverter.ToUInt32(originalData, 0);

            // 回显时间戳应该与原始时间戳不同（服务器会更新）
            if (echoTimestamp == originalTimestamp)
            {
                Console.WriteLine("Warning: Echo timestamp matches original timestamp");
            }

            return true;
        }

        /// <summary>
        /// 宽松验证回显数据（用于测试环境）
        /// </summary>
        /// <param name="echoData">回显数据</param>
        /// <param name="originalData">原始数据</param>
        /// <returns>回显数据是否基本正确</returns>
        public static bool ValidateEchoDataRelaxed(byte[] echoData, byte[] originalData)
        {
            if (echoData == null || originalData == null)
            {
                return false;
            }

            if (echoData.Length != originalData.Length)
            {
                return false;
            }

            // 在测试环境下，我们可以更宽松地验证
            // 只检查数据包的基本结构，不要求严格的回显
            return echoData.Length == 1540; // 1536 + 4
        }
    }
}
